/*
 * userManager.h
 *
 *  Created on: Jun 16, 2011
 *      Author: peckb1
 */

#ifndef USERMANAGER_H_
#define USERMANAGER_H_

#include "syscall.h"

#include "userSharedDefinitions.h"
#include "userCashRegister.h"
#include "userClerk.h"
#include "userLocks.h"
#include "userCustomer.h"
#include "userStockboy.h"
#include "usercommon.h"


void IncreaseSales_Manager(int newVal) {
    (theLocksInHomeDepotEntry.totalStoreSales) += newVal;
}

int GetTotalSales_Manager() {
    return theLocksInHomeDepotEntry.totalStoreSales;
}

void SetTotalSales_Manager(int newVal) {
    theLocksInHomeDepotEntry.totalStoreSales = newVal;
}



void ManagerDoWork() {
	int doWork;
	int collectAllTills;
	int i;
	int registerId;
	int registerStatusLock;
	int registerLock;
	int registerStatusCV;
	int currentRegister;
	int shouldIgnoreCurrentCashRegiter;
	int tillAmount;
	int clerksOnBreak;
	int clerkLineLock;
	int waitForClerksToReturn;
	int anyItemNeedsToBeRestocked;
	int reStockLock;
	int cnt;
	int customersWaitingLock;
	int customersInServiceArea;
	int stockBoysBreakLock;
	int m;
	int tmp;
	int peopleWaiting;
	int numOfAdditionalLoops = 0;
    doWork = TRUE;
    collectAllTills = FALSE;
    for (i = 0; i < 20; i++) {
        Yield();
    }

    while (doWork==TRUE) {
        /* srand (time(NULL)); */
        int randomVar = Rand(100);
        if (randomVar <= 20) {
            #ifdef PRINT_OUTPUT_MANAGER
                printf_3("------- Total Sale of the store until now is $[",(theLocksInHomeDepotEntry.totalStoreSales), "]-------\n");
            #endif
        }

        if (randomVar <= 2 || collectAllTills == TRUE) {
            #ifdef PRINT_EXTRA_LOG_MANAGER
                printf("MANAGER# lets empty till\n");
            #endif

            for (registerId = 0; registerId < MAX_CLERKS; registerId++) {
                registerStatusLock = theLocksInHomeDepotEntry._registerLock[registerId];
                registerLock = theLocksInHomeDepotEntry._fromRegisterInteractionLock[registerId];
                registerStatusCV = theLocksInHomeDepotEntry._registerCV[registerId];
                peopleWaiting = theLocksInHomeDepotEntry._peopleWaitingForCashRegiterLock[registerId];
                currentRegister = registerId;
                #ifdef PRINT_EXTRA_LOG_CASH_REGISTER
                    #ifdef PRINT_EXTRA_LOG_MANAGER
                        printf_3("MANAGER#: Lets acquire the lock for Cash register", registerId, "\n");
                    #endif
                #endif

                shouldIgnoreCurrentCashRegiter = FALSE;

                #ifdef PRINT_EXTRA_LOG_MANAGER
                    printf_3("MANAGER: is going to acquire the lock for register#", registerId, "\n");
                #endif

                Acquire(registerStatusLock);

                #ifdef PRINT_EXTRA_LOG_MANAGER
                    printf_3("MANAGER: acquired the lock for register#", registerId, "\n");
                #endif

                if (theLocksInHomeDepotEntry._managerEmtpyingTill[currentRegister] == -2) { /* cash register not initialized yet */
                    shouldIgnoreCurrentCashRegiter = TRUE;
                } else {
                    while (theLocksInHomeDepotEntry._managerEmtpyingTill[currentRegister] != -1) {  /* ||  _theLocks->_peopleWaitingForCashRegister[currentRegister] > 0) { */
                        if (collectAllTills == TRUE) {
                        	Acquire(peopleWaiting);
                        	Release(registerStatusLock);
							#ifdef PRINT_EXTRA_LOG_MANAGER
                                printf_3("MANAGER: is going to wait for  register#", registerId, "\n");
                            #endif
                            theLocksInHomeDepotEntry._managerWantsToInteract[currentRegister]=0;
                        	do
                        	{
                        		(theLocksInHomeDepotEntry._peopleWaitingForCashRegister[currentRegister])++;
                        		Wait(theLocksInHomeDepotEntry._peopleWaitingForCashRegiterCV[currentRegister], peopleWaiting);
                        	}while(theLocksInHomeDepotEntry._managerWantsToInteract[currentRegister]!=1);
                            #ifdef PRINT_EXTRA_LOG_MANAGER
                                printf_3("MANAGER: Just got woken up from cash register #", registerId, "\n");
                            #endif
                            theLocksInHomeDepotEntry._managerWantsToInteract[currentRegister]=-1;
                            Acquire(registerStatusLock);
                            Release(peopleWaiting);
                        } else {
                            /* cash register busy, lets continue to other cash registers */
                            shouldIgnoreCurrentCashRegiter = TRUE;
                            break;
                        }
                    }
                }

                if (shouldIgnoreCurrentCashRegiter==TRUE) {
                    Release(registerStatusLock);
                }
                else
                {
                	Signal(theLocksInHomeDepotEntry._registerCV[registerId], registerStatusLock);
                	Acquire(registerLock);
					theLocksInHomeDepotEntry._managerEmtpyingTill[registerId] = 1;
					Release(registerStatusLock);
					/* Lets wait for cash register till to put its till in shared memory */
					#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
						#ifdef PRINT_EXTRA_LOG_MANAGER
							printf_3("MANAGER#: Lets wait for Cash register ", registerId, " to provide its till\n");
						#endif
					#endif
					Wait(theLocksInHomeDepotEntry._fromRegisterInteractionCV[registerId], registerLock);
					tillAmount = theLocksInHomeDepotEntry._moneyToTransfer[registerId];
					IncreaseSales_Manager(tillAmount);
					/* Pickup the till balance */
					#ifdef PRINT_OUTPUT_MANAGER
						printf_3("Manager emptied Cash Register [", registerId, "] drawer.\n");
						printf_3("Manager has total sale of $[", (theLocksInHomeDepotEntry.totalStoreSales), "].\n");
					#endif

					Signal(theLocksInHomeDepotEntry._toRegisterInteractionCV[registerId], registerLock);
					Release(registerLock);
                }
            }
        }

        /* check the clerk lines to see if any Clerks signaled us for help */
        #ifdef PRINT_EXTRA_LOG_MANAGER
            printf("MANAGER: is going to acquire signalManagerClerkhelp \n");
        #endif

        Acquire(theLocksInHomeDepotEntry._signalManagerClerkHelp);

        #ifdef PRINT_EXTRA_LOG_MANAGER
            printf("MANAGER: acquired signalManagerClerkhelp \n");
        #endif

        for (i = 0; i < MAX_CLERKS; i++) {
            /* did a clerk signal us? */
            if (theLocksInHomeDepotEntry._storeNeedsMoreClerks[i] == TRUE) {
                /* tell the observer */

                #ifdef PRINT_OUTPUT_MANAGER
                    printf_3("Manager got a call from Clerk [", i, "]\n");
                #endif
                /* turn off the clerk's signal */
                theLocksInHomeDepotEntry._storeNeedsMoreClerks[i] = FALSE;

                /* get the lock for waking up a clerk */
                Acquire(theLocksInHomeDepotEntry._clerksOnBreakLock);

                /* check to see if there are any clerks to awaken */
                clerksOnBreak = theLocksInHomeDepotEntry._clerksOnBreakMV;

                if (clerksOnBreak > 0) {
                    #ifdef PRINT_OUTPUT_MANAGER
                        printf("Manager wakes up Clerk.\n");
                    #endif

                    /* decrement the counter */
                    theLocksInHomeDepotEntry._clerksOnBreakMV--;

                    /* signal the next Clerk to Wake up */
                    Signal(theLocksInHomeDepotEntry._clerksOnBreakCV, theLocksInHomeDepotEntry._clerksOnBreakLock);
                }

                /* release the lock for waking a clerk */
                Release(theLocksInHomeDepotEntry._clerksOnBreakLock);
                break;
            }
        }
        /* we're done looking at the signals from the clerk */
        Release(theLocksInHomeDepotEntry._signalManagerClerkHelp);

        /*
         * Lets see if customers need to work with clerks but all of the are in break
         */
        clerkLineLock = theLocksInHomeDepotEntry._clerkLinelock;
        waitForClerksToReturn = theLocksInHomeDepotEntry._customerNeedsClerkAssitanceLock;

        Acquire(waitForClerksToReturn);

        if (theLocksInHomeDepotEntry._customersNeedingAsistanceMV > 0) {
            #ifdef PRINT_EXTRA_LOG_MANAGER
                printf_3("MANAGER: There are ", theLocksInHomeDepotEntry._customersNeedingAsistanceMV, " customers waiting for clerk\n");
            #endif

            /* get the lock for waking up a clerk */
            Acquire(theLocksInHomeDepotEntry._clerksOnBreakLock);

            /* check to see if there are any clerks to awaken */
            if (theLocksInHomeDepotEntry._clerksOnBreakMV > 0) {
                #ifdef PRINT_OUTPUT_MANAGER
                    printf("Manager wakes up Clerk.\n");
                #endif

                /* decrement the counter */
                theLocksInHomeDepotEntry._clerksOnBreakMV--;

                /* signal the next Clerk to Wake up */
                Signal(theLocksInHomeDepotEntry._clerksOnBreakCV, theLocksInHomeDepotEntry._clerksOnBreakLock);
            } else {
                #ifdef PRINT_EXTRA_LOG_MANAGER
                    printf("MANAGER Cant wake up any Clerk since no one is in break.\n");
                #endif
            }

            Release(theLocksInHomeDepotEntry._clerksOnBreakLock);
        }
        Release(waitForClerksToReturn);

        /*
         * Lets check on stockboys and see if we need call any to return from break
         * if any customer is waiting for an item to be restocked OR
         * any customer is waiting in service area go ahead and wake up a stockboy
         */
        anyItemNeedsToBeRestocked = FALSE;

        reStockLock = theLocksInHomeDepotEntry._customerWaitingForReStockLock;

        #ifdef PRINT_LOCKS_STOCKBOY
            /* printf("Manager reStockLock->Acquire()!\n"); */
        #endif

        Acquire(reStockLock);

        #ifdef PRINT_LOCKS_STOCKBOY
            /* printf("Manager reStockLock->Acquire() Done!\n"); */
        #endif

        for (cnt = 0; cnt < MAX_ITEMS; cnt++) {
            if(theLocksInHomeDepotEntry._customersWaitingForRestock[cnt] > 0 &&
               theLocksInHomeDepotEntry._stockBoyReStockingItem[cnt] == NOT_FOUND) {
				#ifdef PRINT_EXTRA_LOG_MANAGER
                	printf_3("MANAGER item#", cnt," needs restocking\n");
            	#endif
                anyItemNeedsToBeRestocked = TRUE;
            }
        }

        #ifdef PRINT_LOCKS_STOCKBOY
            /* printf("Manager reStockLock->Relase()!\n"); */
        #endif

        Release(reStockLock);

        #ifdef PRINT_LOCKS_STOCKBOY
            /* printf("Manager reStockLock->Release() Done!\n"); */
        #endif

        customersWaitingLock = theLocksInHomeDepotEntry._customersWaitingInAisleToAskQuestionLock[SERVICE_AREA_LINE];

        #ifdef PRINT_EXTRA_LOG_MANAGER
            printf("MANAGER: Going to acquired the customers waiting lock\n");
        #endif

        Acquire(customersWaitingLock);

        customersInServiceArea = theLocksInHomeDepotEntry._customersWaitingInAisleToAskQuestionMV[SERVICE_AREA_LINE];
        if (customersInServiceArea>0)
        {
			#ifdef PRINT_EXTRA_LOG_MANAGER
                printf("MANAGER# there are customers waiting in service area\n");
            #endif
        }
        Release(customersWaitingLock);

        if (anyItemNeedsToBeRestocked == TRUE || customersInServiceArea > 0) {
            /* Waking up a stock boy */
            stockBoysBreakLock = theLocksInHomeDepotEntry._stockBoyBreakLock;
            Acquire(stockBoysBreakLock);

            if (theLocksInHomeDepotEntry._stockBoyOnBreakMV > 0) {
                Signal(theLocksInHomeDepotEntry._stockBoysOnBreakCV, stockBoysBreakLock);

                #ifdef PRINT_OUTPUT_MANAGER
                    printf("Manager wakes up stock boy.\n");
                #endif

                theLocksInHomeDepotEntry._stockBoyOnBreakMV--;
            }

            Release(stockBoysBreakLock);
        }
        for (m = 0; m < 100; m++) {
            Yield();
        }



        Acquire(theLocksInHomeDepotEntry._occupancyLock);

        if (theLocksInHomeDepotEntry._customersInStore == 0) {
        	numOfAdditionalLoops++;
            Release(theLocksInHomeDepotEntry._occupancyLock);

            if (collectAllTills == FALSE && numOfAdditionalLoops ==1) {

                Acquire(theLocksInHomeDepotEntry._clerksOnBreakLock);
                /* check to see if there are still working */

                if (theLocksInHomeDepotEntry._clerksOnBreakMV == MAX_CLERKS) {
                    Release(theLocksInHomeDepotEntry._clerksOnBreakLock);
                    Acquire(theLocksInHomeDepotEntry._stockBoyBreakLock);

                    if (theLocksInHomeDepotEntry._stockBoyOnBreakMV == MAX_STOCKBOYS) {
                        Release(theLocksInHomeDepotEntry._stockBoyBreakLock);
                        /* Everyone is out, we can collect all of the tills now */
                        collectAllTills = TRUE;
                    } else {
                        Release(theLocksInHomeDepotEntry._stockBoyBreakLock);
                    }
                } else {
                    Release(theLocksInHomeDepotEntry._clerksOnBreakLock);
                }
            } else {

                #ifdef PRINT_EXTRA_LOG_MANAGER
                    printf("MANAGER: no one in the store, manager can close up.\n");
                #endif

                for (tmp = 0; tmp < MAX_CLERKS; tmp++) {
                    printf_5("Total Sale from Cash Register [", tmp, "] is $[", theLocksInHomeDepotEntry.registerSales[tmp] ,"]\n");
                }

                printf_3("Total Sale of the entire store is $[", theLocksInHomeDepotEntry.totalStoreSales, "]\n");
                return;
            }
        } else {
            Release(theLocksInHomeDepotEntry._occupancyLock);
        }
    }
}

#endif /* USERMANAGER_H_ */
